﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Crap4Net.CoverageParsers
{
    public class VsXmlParser : BaseCoverageParser
    {
        protected override void ParseDataFromXml(string reportFileName)
        {
            var NameSpaces = GetNameSpaces(reportFileName);
            foreach (var nameSpaceElem in NameSpaces)
            {
                var classes = GetAllClasses(nameSpaceElem);
                foreach (var type in classes)
                {
                    var methods = GetAllMethods(type);
                    foreach (var method in methods)
                    {
                        var methodSignature = GetMethodSignature(nameSpaceElem, type, method);
                        var covValue = GetCoverageValue(method);
                        Data.Add(
                            new CoverageDataEntry(methodSignature, covValue)
                            );
                    }
                }
            }
        }
        private IList<XElement> GetNameSpaces(string reportFileName)
        {
            var document = XDocument.Load(reportFileName);

            var result = from nSpace in document.Descendants()
                         where nSpace.Name.LocalName == "NamespaceTable"
                         select nSpace;
            return result.ToList();
        }

        private IList<XElement> GetAllClasses(XElement nameSpace)
        {

            var result = from type in nameSpace.Descendants()
                         where type.Name.LocalName == "Class"
                         select type;

            return result.ToList();
        }

        private IList<XElement> GetAllMethods(XElement type)
        {
            var result = from method in type.Descendants()
                         where method.Name.LocalName == "Method"
                         select method;

            return result.ToList();
        }

        private MethodSignature GetMethodSignature(XElement nameSpaceElem, XElement type, XElement method)
        {
            var assemblyname = GetAssemblyName(nameSpaceElem);
            var nameSpace = GetNameSpaceString(nameSpaceElem);
            var className = GetClassName(type);
            var methodName = GetMethodName(method);
            var args = GetMethodArgs(method);
            var methodSignature = new MethodSignature(assemblyname, nameSpace, className, methodName, args);
            return methodSignature;
        }

        private string GetAssemblyName(XElement nameSpaceElem)
        {
            return nameSpaceElem.Parent.Element("ModuleName").Value;
        }

        private string GetNameSpaceString(XElement nameSpace)
        {
            return nameSpace.Element("NamespaceName").Value;
        }

        private string GetClassName( XElement type)
        {
            return type.Element("ClassName").Value;
        }

        private string GetMethodName(XElement method)
        {
            
            var fullName = method.Element("MethodName").Value;
            return fullName.Split(new char[]{'('})[0];
        }

        private string[] GetMethodArgs(XElement method)
        {
            var fullName = method.Element("MethodName").Value;
            int start = fullName.IndexOf('(');
            int end = fullName.IndexOf(')');
            var args = fullName.Substring(start + 1, end - start - 1);
            if (string.IsNullOrEmpty(args))
                return new string[0];
            else
                return args.Split(new char[] { ',' });
        }

        private int GetCoverageValue(XElement method)
        {
            int blockCovered = int.Parse(method.Element("BlocksCovered").Value);
            int blockNotcovered = int.Parse(method.Element("BlocksNotCovered").Value);
            return blockCovered * 100 / (blockCovered + blockNotcovered);
        }
    }
}
